<?php
/**
 * CLI 基类
 */
require_once ('DB.php');
require_once ('thread_base.php');
/**
 * Worker 线程环境
 * 反射初始化对象
 * 任务中调用 $this->worker->getObj(); 获取对象
 * data 后续扩展
 */
class TrEnvironment extends Worker{
    private $obj_name;//需要实例化对象名
    function __construct($obj_name)
    {
        $this->obj_name = $obj_name;
    }

    function run()
    {
    }

    public function initObj($task_name){
        $class = new ReflectionClass($this->obj_name);
        $obj = $class->newInstanceArgs(array(true));
        $obj->tr_name = $task_name;
        return $obj;
    }
    function setGarbage()
    {
        parent::setGarbage(); // TODO: Change the autogenerated stub
    }
}

/**
 * 多线程模板类
 * 继承此类 此类已经调用init()方法初始化了,不需要再子类中重新初始化
 * 重写 initialize() 方法作为子类初始化
 * 设置好$tr_limit_number参数 线程数量后调用tr_init(__CLASS__)方法初始化线程池
 * 重写 task($tr) 任务类
 * 在主线程函数中调用task_open()传递任务所需参数(需支持序列化),传递任务名(不传递,随机生成)返回线程名和任务名
 * Class objectTrBase
 * 
 * DB类中初始化了数据库
 */
class objectTrBase extends DB{
    //线程池
    var $tr_pool;
    //任务池 通过此任务名可以修改子线程中正在运行时任务的参数
    var $task_pool;
    //子线程通过反射子类实例化后名称 主线程中为子类的__CLASS__变量值,子线程中为task_name值
    var $tr_name;
    //线程限制数量 默认为不限制
    var $tr_limit_number;
    /**
     * 本类初始化
     * objectTrBase constructor.
     * @param bool $is_no_main 如果是false本类不会初始化也不会调用main方法执行逻辑,如果是true反之
     */
    function __construct($is_no_main = false)
    {
        //初始化数据库
        $this->init();
        if (!$is_no_main){
            $this->tr_limit_number = 8;//默认值
            $this->initialize();
        }
    }

    /**
     * 线程初始化
     * @param $obj_name 传递 __CLASS__ 变量即可
     */
    function tr_init($obj_name){
        $this->tr_name = $obj_name;
        $this->tr_pool = new Pool($this->tr_limit_number, 'TrEnvironment',array($obj_name));
    }

    /**
     * 修改线程池数量
     * @param $size 整数 int
     */
    function tr_resize($size){
        $this->tr_pool->resize($size);
    }

    /**
     * 初始化函数,子线程对象初始化不会调用此函数
     * 子线程需要初始化,请在tr_init($data)函数中初始化
     * 在方法中调用主线程正常业务代码
     */
    function initialize(){
    }

    /**
     * 开启一个线程
     * @param $data 参数  传递的参数必须要保证可以序列化,不要直接传递对象!!!!
     * @param $task_name 任务名称 默认为false 随机生成
     * @return array 内部两个属性task_name 任务队列中名称用于修改线程参数 , worker_name线程池中环境对象标识符
     */
    function task_open($data,$task_name = false){

        $task_name = $task_name ? $task_name:get_random_code(16,3);
        $re = new threadBase($this->tr_name,$data,$task_name);
        $worker_name = $this->tr_pool->submit($re);
        $this->task_pool[$task_name] = $re;
        return array(
            "task_name" => $task_name,
            "worker_name" => $worker_name
        );
    }

    /**
     * 主动通过state关闭所有线程池线程
     */
    function tr_close(){
        //等待队列中执行完成
        $this->tr_pool->shutdown();
    }

    /**
     * 子线程会反射调用此方法,$tr为线程对象
     * 任务类
     * @param $tr 线程对象 判断内部$state属性是否为true,为true表示线程已结束,主线程传递的参数在$data属性中
     */
    function task($tr){
    }

    /**
     * 回收已完成的任务
     */
    function task_clear(){
        //回收已完成的对象
        while ($this->tr_pool->collect(function($work){
            return $work->isGarbage();
        })) continue;
    }

    /**
     * 通过task队列名获取data数组
     * @param $task_name
     * @return array
     */
    function get_task_data_by_name($task_name){
        return $this->task_pool[$task_name]->data;
    }

    /**
     * 设置task队列中的data数组$key和$val
     * @param $task_name
     * @param $key
     * @param $val
     */
    function set_task_data_by_name($task_name,$key,$val){
        $this->task_pool[$task_name]->data[$key] = $val;
    }

    /**
     * 通过task队列名获取data数组中指定的key的$val
     * @param $task_name
     * @return array[$key]
     */
    function get_task_data_by_name_and_key($task_name,$key){
        return $this->task_pool[$task_name]->data[$key];
    }
}